Una paleta de colores es un conjunto de tonos que se utilizan juntos para crear un efecto armonioso, coherente y atractivo en las representaciones visuales (diseño gráfico, cine, fotografía, pintura, etc.), así como para transmitir mensajes y generar emociones determinados, de acuerdo con la intencionalidad del autor de la obra.
En un contexto de amplia demanda de herramientas que puedan asistir a diseñadores gráficos, directores de arte, pintores y creadores de contenido, entre otros, para la selección rápida y adecuada de los colores apropiados para sus obras, una aplicación para configurar paletas de colores a partir de imágenes sería de mucha utilidad.
Una vía para lograr una herramienta como esta es utilizar técnicas de machine learning no supervisado sobre imágenes para visualizar la distribución de los colores presentes en estas y generar, de manera automática, modelos de paletas de colores. En esta primera aproximación el método va a permitir identificar los colores en una imagen para construir un muestrario por similitud de píxeles, lo cual puede ser muy útil para estudios de marketing, psicología, medicina, arte, ambiente, entre otros. Por ejemplo, se podrían extraer los colores de las diferentes superficies de la Tierra en una imagen satelital para estudiar la distribución de la vegetación o de la contaminación.
Los datos están asociados con imágenes de obras de arte. Pueden ser descargados a partir de este enlace.
Recopilación de las imágenes a partir del repositorio. La idea es seleccionar un conjunto diverso de muestras en diferentes estilos artísticos (no más de 10).
Preparación de las imágenes para el entrenamiento y prueba del modelo. Para este paso construir un pipeline que integre las transformaciones que se consideren adecuadas.
Desarrollo del modelo de agrupación para identificar los colores presentes en las imágenes.
Creación de un modelo que transforme los grupos de colores identificados en un muestrario representativo. Adicionalmente, se debe mostrar la distribución de los colores de la imagen en un espacio de dos dimensiones utilizando t-SNE.
NOTA: La calificación será sobre notebook ejecutado.
El algoritmo de agrupación a utilizar queda a consideración de cada grupo, pero es importante justificar la elección.
Se debe evidenciar el desempeño del método construido mostrando la paleta para al menos cuatro (4) imágenes de diferentes estilos, con la visualización de la distribución de colores en el espacio de dos dimensiones.
Un diagrama general del método que se quiere desarrollar se muestra en la siguiente figura:
Este código en su mayoría está basado en: "https://www.kaggle.com/code/juandaviddev/color-palette/notebook"
import pandas as pd
import numpy as np
import os
import os.path as osp
import pandas as pd
import requests
from sklearn.preprocessing import StandardScaler, RobustScaler
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import KMeans, DBSCAN, AgglomerativeClustering
from sklearn.decomposition import PCA, IncrementalPCA
from sklearn.metrics import silhouette_score, silhouette_samples, rand_score
from scipy.cluster.hierarchy import dendrogram, linkage
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import seaborn as sns
import os
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import AgglomerativeClustering
from sklearn.metrics import silhouette_score
pd.set_option('display.max_colwidth', None)
img_classes = pd.read_csv("Data/classes.csv")
sample_10 = pd.read_csv("Data/sample_10.csv", header=None)
lista = sample_10[0].unique()
img_selected = []
diccio = {}
for img in range(len(lista)):
url =lista[img].split("4202543/")[1].split("?X-Goog-Algorithm")[0]
img_selected.append(url)
diccio[url] = lista[img][1:-1]
img_selected
['Contemporary_Realism/lucian-freud_factory-in-north-london.jpg', 'Early_Renaissance/filippo-lippi_disputation-in-the-synagogue-detail-1465.jpg', 'Impressionism/armand-guillaumin_moulins-en-hollandee-1904.jpg', 'Cubism/albert-gleizes_untitled-3.jpg', 'Naive_Art_Primitivism/andre-bauchant_le-bouquet-1928.jpg', 'Northern_Renaissance/albrecht-altdorfer_the-battle-of-issus-1529.jpg', 'Pop_Art/aldo-mondino_collage-1973.jpg', 'Symbolism/a.y.-jackson_smart-river-alaska-1945.jpg', 'Fauvism/andre-derain_figures-from-a-carnival.jpg', 'Art_Nouveau_Modern/aladar-korosfoi-kriesch_lady-with-tiara.jpg']
filtered_img_classes = img_classes[img_classes['filename'].isin(img_selected)]
filtered_img_classes
| filename | artist | genre | description | phash | width | height | genre_count | subset | |
|---|---|---|---|---|---|---|---|---|---|
| 2262 | Art_Nouveau_Modern/aladar-korosfoi-kriesch_lady-with-tiara.jpg | aladar korosfoi kriesch | ['Art Nouveau Modern'] | lady-with-tiara | cc2bb3d64c799039 | 1382 | 1740 | 1 | train |
| 10485 | Contemporary_Realism/lucian-freud_factory-in-north-london.jpg | lucian freud | ['Contemporary Realism'] | factory-in-north-london | ddc75638863a2ac6 | 1394 | 1382 | 1 | train |
| 10622 | Cubism/albert-gleizes_untitled-3.jpg | albert gleizes | ['Cubism'] | untitled-3 | cfb63198ce649893 | 1936 | 1382 | 1 | train |
| 12821 | Early_Renaissance/filippo-lippi_disputation-in-the-synagogue-detail-1465.jpg | filippo lippi | ['Early Renaissance'] | disputation-in-the-synagogue-detail-1465 | 81367edb17564c4a | 1382 | 1921 | 1 | train |
| 18528 | Fauvism/andre-derain_figures-from-a-carnival.jpg | andre derain | ['Fauvism'] | figures-from-a-carnival | b08bcd2083f2decd | 1897 | 1382 | 1 | train |
| 21099 | Impressionism/armand-guillaumin_moulins-en-hollandee-1904.jpg | armand guillaumin | ['Impressionism'] | moulins-en-hollandee-1904 | 9ef2e00149ff0f31 | 1718 | 1382 | 1 | train |
| 32815 | Naive_Art_Primitivism/andre-bauchant_le-bouquet-1928.jpg | andre bauchant | ['Naive Art Primitivism'] | le-bouquet-1928 | c296591b37643ccb | 1382 | 1658 | 1 | train |
| 34999 | Northern_Renaissance/albrecht-altdorfer_the-battle-of-issus-1529.jpg | albrecht altdorfer | ['Northern Renaissance'] | the-battle-of-issus-1529 | 9d8cc47c2c8cea4f | 1382 | 1784 | 1 | train |
| 59251 | Symbolism/a.y.-jackson_smart-river-alaska-1945.jpg | a.y. jackson | ['Symbolism', 'Art Nouveau Modern'] | smart-river-alaska-1945 | d23fa9a0d78f0d28 | 1877 | 1382 | 2 | train |
| 73379 | Pop_Art/aldo-mondino_collage-1973.jpg | aldo mondino | ['Pop Art'] | collage-1973 | ba23c43f93c4f8c2 | 1382 | 1742 | 1 | test |
filtered_img_classes.loc[:, 'url'] = filtered_img_classes['filename'].map(diccio)
/var/folders/r5/cc3y743j5ys_g9v6b67d72jh0000gn/T/ipykernel_25150/4201899911.py:1: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy filtered_img_classes.loc[:, 'url'] = filtered_img_classes['filename'].map(diccio)
def download_image(url, filename):
response = requests.get(url)
os.makedirs(os.path.dirname(filename), exist_ok=True)
with open(filename, 'wb') as f:
f.write(response.content)
for index, row in filtered_img_classes.iterrows():
url = row['url']
filename = row['filename']
download_image(url, filename)
from PIL import Image
def load_image(filename):
try:
img = Image.open(filename)
img = img.convert("RGB")
return img
except FileNotFoundError:
return None
filtered_img_classes.loc[:, 'image'] = filtered_img_classes['filename'].apply(load_image)
/var/folders/r5/cc3y743j5ys_g9v6b67d72jh0000gn/T/ipykernel_25150/4036918011.py:11: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy filtered_img_classes.loc[:, 'image'] = filtered_img_classes['filename'].apply(load_image)
import matplotlib.pyplot as plt
image = filtered_img_classes["image"].iloc[0]
plt.imshow(image)
plt.show()
En el preprocesamiento de las diez imágenes, se realizaron los siguientes pasos:
Se realiza interpolación utilizando el método de interpolación INTER_AREA que considera los pixeles vecinos y sus colores para calcular el color de un pixel nuevo al redimensionar una imagen. Este método de interpolación mantiene la nitidez y la claridad de las imágenes a diferencia de otros.
Una vez que se ha hecho el resize, se transforma la imagen a dataframe donde cada canal R,G,B se transforma en una columna distinta y cada fila es un pixel distinto. Esto se realizó con el fin de mantener las características de cada canal.
Por otro lado, al realizar el pipeline este tiene los siguientes pasos:
import pandas as pd
import numpy as np
import os
import cv2
import random
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import seaborn as sns
from sklearn.decomposition import PCA
from sklearn.manifold import TSNE
from sklearn.cluster import KMeans, MeanShift, estimate_bandwidth
from sklearn.metrics import silhouette_score, silhouette_samples
from sklearn.cluster import DBSCAN
from sklearn.preprocessing import StandardScaler
class ImageReader:
"""Class to read and preprocess images.
Attributes:
- n_images (int): Number of images to read
- file_type (str): File type of the images
- directory (str): Directory where the images are stored
Preprocessing includes:
- Reading the images
- Rescaling the images keeping the aspect ratio
"""
def __init__(self, filtered_img: pd.DataFrame, scale: float = 0.1):
self.images_names = []
self.filter = filtered_img
self.n_images = len(self.filter)
self.original = self.read_images()
self.images = self.read_images()
self.images = self.rescale_images(self.images, scale)
def read_images(self):
"""Read images from a directory and store them in a list"""
images = []
for filename in self.filter["filename"]:
image = cv2.imread(filename)
if image is not None:
images.append(image)
self.images_names.append(filename)
return images
def rescale_images(self, images: list, scale: float = 0.5):
"""Rescale images keeping the aspect ratio"""
rescaled_images = []
for image in images:
width = int(image.shape[1] * scale)
height = int(image.shape[0] * scale)
dim = (width, height)
rescaled_image = cv2.resize(image, dim, interpolation=cv2.INTER_AREA)
rescaled_images.append(rescaled_image)
return rescaled_images
def plot_images(self):
"""Plot the images"""
n_cols = 2
n_rows = int(np.ceil(self.n_images / n_cols))
fig, axs = plt.subplots(n_rows, n_cols)
for i, ax in enumerate(axs.flat):
if i < self.n_images:
ax.imshow(cv2.cvtColor(self.images[i], cv2.COLOR_BGR2RGB))
ax.axis('off')
plt.show()
class ImageDataProcessor:
"""Class to process images and extract features.
Attributes:
- image_reader: Instance of the ImageReader class.
Methods:
- extract_features: Extract features from the images
"""
def __init__(self, image_reader: ImageReader):
self.image_reader = image_reader
if len(self.image_reader.images) > 1:
self.image_reader.images = self.resize_images((100, 100))
self.features = self.extract_features()
def extract_features(self):
"""Create DataFrame with RGB values of the images"""
features = []
for image in self.image_reader.images:
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
image = image.reshape((image.shape[0] * image.shape[1], 3))
features.append(image)
features = np.concatenate(features, axis=0)
features = pd.DataFrame(features, columns=['r', 'g', 'b'])
return features
def resize_images(self, size: tuple):
"""Resize images to a given size"""
resized_images = []
for image in self.image_reader.images:
resized_image = cv2.resize(image, size, interpolation=cv2.INTER_AREA)
resized_images.append(resized_image)
return resized_images
images = ImageReader(filtered_img=filtered_img_classes)
images.plot_images()
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.cluster import KMeans, MeanShift, estimate_bandwidth, DBSCAN, AgglomerativeClustering, SpectralClustering, MeanShift
from sklearn.metrics import silhouette_score, silhouette_samples
class ImageClustering:
"""Class to cluster images using different clustering algorithms.
Attributes:
- image_data_processor: Instance of the ImageDataProcessor class.
- clusterer: Clustering algorithm to use.
- kwargs: Additional parameters for the clustering algorithm.
Methods:
- fit: Fit the clustering algorithm to the data.
- plot_clusters: Plot the images and their respective clusters.
"""
def __init__(self, image_data_processor: ImageDataProcessor, clusterer, **kwargs):
self.image_data_processor = image_data_processor
self.clusterer = clusterer
self.kwargs = kwargs
self.pipeline = self.create_pipeline()
def create_pipeline(self):
"""Create a pipeline for the clustering algorithm"""
pipeline = Pipeline([
('scaler', StandardScaler()),
('clusterer', self.clusterer(**self.kwargs))
])
return pipeline
def fit(self):
"""Fit the clustering algorithm to the data"""
self.pipeline.fit(self.image_data_processor.features)
def predict_one(self, image):
"""Predict the cluster of a single image"""
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
image = image.reshape((image.shape[0] * image.shape[1], 3))
return self.pipeline.named_steps['clusterer'].predict(image)
def plot_clusters(self):
"""Plot the images and their respective clusters"""
# get cluster labels
cluster_labels = self.pipeline.named_steps['clusterer'].labels_
n_clusters = len(np.unique(cluster_labels))
centroids = self.pipeline.named_steps['clusterer'].cluster_centers_
rgb_values = self.pipeline.named_steps['scaler'].inverse_transform(centroids)
rgb_values = rgb_values / 255
def _add_infig_color_palette(fig, rgb_values, n_clusters):
# add color palette to the figure
ax = fig.add_axes([0.1, 0.9, 0.1, 0.1])
ax.imshow([rgb_values], aspect='auto')
ax.axis('off')
ax.set_title('Color palette')
return fig
if len(self.image_data_processor.image_reader.images) == 1:
fig, ax = plt.subplots(1, 1)
ax.imshow(cv2.cvtColor(self.image_data_processor.image_reader.original[0], cv2.COLOR_BGR2RGB))
ax.axis('off')
else:
n_cols = 3
n_rows = int(np.ceil(len(self.image_data_processor.image_reader.original) / n_cols))
fig, axs = plt.subplots(n_rows, n_cols)
for i, ax in enumerate(axs.flat):
if i < len(self.image_data_processor.image_reader.images):
ax.imshow(cv2.cvtColor(self.image_data_processor.image_reader.original[i], cv2.COLOR_BGR2RGB))
ax.axis('off')
fig = _add_infig_color_palette(fig, rgb_values, n_clusters)
plt.show()
class ClusteringEvaluator:
"""Class to evaluate performance of clustering algorithms.
Attributes:
- image_data_processor: Instance of the ImageDataProcessor class.
- image_clustering: Instance of the ImageClustering class.
Methods:
- silhouette_score: Compute the silhouette score of the clustering algorithm.
- silhouette_plot: Plot the silhouette plot of the clustering algorithm.
"""
def __init__(self, image_data_processor: ImageDataProcessor, image_clustering: ImageClustering):
self.image_data_processor = image_data_processor
self.image_clustering = image_clustering
def silhouette_score(self):
"""Compute the silhouette score of the clustering algorithm"""
cluster_labels = self.image_clustering.pipeline.named_steps['clusterer'].labels_
score = silhouette_score(self.image_data_processor.features, cluster_labels)
return score
def silhouette_plot(self):
"""Plot the silhouette plot of the clustering algorithm"""
cluster_labels = self.image_clustering.pipeline.named_steps['clusterer'].labels_
silhouette_values = silhouette_samples(self.image_data_processor.features, cluster_labels)
y_lower = 10
fig, ax = plt.subplots(1, 1, figsize=(8, 8))
for i in range(len(np.unique(cluster_labels))):
cluster_silhouette_values = silhouette_values[cluster_labels == i]
cluster_silhouette_values.sort()
size_cluster_i = cluster_silhouette_values.shape[0]
y_upper = y_lower + size_cluster_i
color = cm.nipy_spectral(float(i) / len(np.unique(cluster_labels)))
ax.fill_betweenx(np.arange(y_lower, y_upper), 0, cluster_silhouette_values, facecolor=color, edgecolor=color, alpha=0.7)
ax.text(-0.05, y_lower + 0.5 * size_cluster_i, str(i))
y_lower = y_upper + 10
ax.set_title('Silhouette plot')
ax.set_xlabel('Silhouette values')
ax.set_ylabel('Cluster label')
ax.axvline(x= self.silhouette_score(), color='red', linestyle='--')
ax.set_yticks([])
plt.show()
class DimReducer:
"""Class to reduce dimensions usin t-sne and pca
Attributes:
- image_processor: ImageProcessor instance
- image_clustering: ImageClustering instance
Methods:
- pca_reduction: reduce dims using pca
- tsne_reduction: reduce dims using t-sne
"""
def __init__(self, image_processor: ImageDataProcessor, image_clustering: ImageClustering) -> None:
self.image_processor = image_processor
self.image_clustering = image_clustering
def get_tsne(self, n_components: int):
"""Run t-sne"""
tsne = TSNE(n_components=n_components)
return tsne.fit_transform(self.image_processor.features)
def plot_tsne_with_cluster_colors(self, n_components: int):
tsne = TSNE(n_components=n_components)
reduced_features = tsne.fit_transform(self.image_processor.features)
cluster_labels = self.image_clustering.pipeline.named_steps['clusterer'].labels_
n_clusters = len(np.unique(cluster_labels))
centroids = self.image_clustering.pipeline.named_steps['clusterer'].cluster_centers_
rgb_values = self.image_clustering.pipeline.named_steps['scaler'].inverse_transform(centroids) / 255
fig, ax = plt.subplots(1, 1, figsize=(5, 5))
for i in range(n_clusters):
cluster_indices = np.where(cluster_labels == i)[0]
ax.scatter(reduced_features[cluster_indices, 0], reduced_features[cluster_indices, 1],
c=[rgb_values[i]], label=f'Cluster {i}')
ax.set_xlabel('First component')
ax.set_ylabel('Second component')
ax.set_title('t-SNE with Cluster Colors')
ax.legend()
plt.show()
K-means es un algoritmo de clusterización, que tiene como objetivo dividir n observaciones en k clusters en los que cada observación pertenece al cluster con la media más cercana (centros de cluster o centroide de cluster), sirviendo como prototipo del grupo. En este método no supervisado, el número k es un hiperparámetro del algoritmo. Para saber el k-óptimo se utiliza el método de la silueta. Este método calcula el coeficiente de la silueta para evaluar la calidad del agrupamiento obtenido. Un valor más alto de este índice indica un caso más deseable del número de clústers. Este se calcula de forma: $s(i) = \frac{b-a}{max(a,b)}$ donde a es el promedio de la distancia de la observación i con las demás observaciones del mismo clúster y b es la distancia mínima a otro clúster.
Por lo tanto, se utiliza el coeficiente de la silueta para determinar el número de clústeres que se deben utilizar en general en las diez imágenes seleccionadas. Además, se decidió utilizar Kmeans sobre otros algorítmos de clusterización porque K-means es un algoritmo de clustering ampliamente utilizado que es simple de implementar, eficiente computacionalmente y es efectivo para encontrar agrupamientos.
En primer lugar, se varía el hiperparámetro k dado que representa determina la cantidad de grupos distintos que se identificarán en el conjunto de datos. En este caso, k representa el número de colores que se eligirán para la paleta de cada imagen. Por otro lado, se eligió variar el hiperparámetro init dado que controla la forma en que se inicializan los centroides. Esta puede ser aleatoria (los centroides se inicializan aleatoriamente) y K-means++ (selecciona iterativamente los centroides de una manera que maximiza la distancia entre ellos). Este hiperparámetro conduce a agrupaciones muy diferentes de los mismos datos por lo que puede llegar a variar el coeficiente de silueta.
Luego de realizar el análisis de los hiperparámetros y variar el número de clústers se obtuvo que el mejor hiperparámetro fue con un número k=5 y init = k-means++, donde el coeficiente de silueta obtuvo un resultado de 0.41059. Por otro lado, no se observó una diferencia significativa entre el hiperparámetro _init k-means++ y random dado que la variación de los resultados es muy baja.
# Lista de hiperparámetros
n_clusters = [5,6,7]
init = ['k-means++', 'random']
image_data_processor = ImageDataProcessor(images)
for i in init:
for n_cluster in n_clusters:
image_clustering = ImageClustering(image_data_processor, KMeans, n_clusters=n_cluster, init = i)
image_clustering.fit()
clustering_evaluator = ClusteringEvaluator(image_data_processor, image_clustering)
print(f'KMeans with {n_cluster} clusters and {i} init: {clustering_evaluator.silhouette_score()}')
clustering_evaluator.silhouette_plot()
KMeans with 5 clusters and k-means++ init: 0.4105965018092948
KMeans with 6 clusters and k-means++ init: 0.3828795773708798
KMeans with 7 clusters and k-means++ init: 0.37425368335169396
KMeans with 5 clusters and random init: 0.41027815142806007
KMeans with 6 clusters and random init: 0.3951178528657418
KMeans with 7 clusters and random init: 0.37417940614720036
Dado que el número de imágenes es bajo (10) se decidió utilizar t-SNE para visualizar los resultados de los clústeres obtenidos en vez de reducir la dimensionalidad antes de aplicar K-Means. t-SNE transforma los datos en un espacio de dimensión reducida que puede visualizarse fácilmente en un plano de dos dimensiones. Utilizar t-SNE al final permite visualizar los resultados del clustering de K-means de una manera intuitiva e interpretable, lo que facilita la identificación de las paletas de colores dominantes en la imagen. Finalmente, usar t-SNE al final permite preservar las relaciones de color entre los pixeles cercanos, lo que resulta en paletas de color más representativas de la imagen original.
Para n_clusters = 5
print(f"KMeans with 5 clusters")
for i in range(len(filtered_img_classes)):
print("Imagen", i+1)
images = ImageReader(filtered_img=filtered_img_classes.iloc[[i]])
image_data_processor = ImageDataProcessor(images)
image_clustering = ImageClustering(image_data_processor, KMeans, n_clusters=5, n_init="auto")
image_clustering.fit()
print("Paleta de colores")
image_clustering.plot_clusters()
dim_reducer = DimReducer(image_data_processor, image_clustering)
print("t-SNE")
dim_reducer.plot_tsne_with_cluster_colors(2)
KMeans with 5 clusters Imagen 1 Paleta de colores
t-SNE
Imagen 2 Paleta de colores
t-SNE
Imagen 3 Paleta de colores
t-SNE
Imagen 4 Paleta de colores
t-SNE
Imagen 5 Paleta de colores
t-SNE
Imagen 6 Paleta de colores
t-SNE
Imagen 7 Paleta de colores
t-SNE
Imagen 8 Paleta de colores
t-SNE
Imagen 9 Paleta de colores
t-SNE
Imagen 10 Paleta de colores
t-SNE
Para n_clusters = 6
print(f"KMeans with 6 clusters")
for i in range(len(filtered_img_classes)):
print("Imagen", i+1)
images = ImageReader(filtered_img=filtered_img_classes.iloc[[i]])
image_data_processor = ImageDataProcessor(images)
image_clustering = ImageClustering(image_data_processor, KMeans, n_clusters=6, n_init="auto")
image_clustering.fit()
print("Paleta de colores")
image_clustering.plot_clusters()
dim_reducer = DimReducer(image_data_processor, image_clustering)
print("t-SNE")
dim_reducer.plot_tsne_with_cluster_colors(2)
KMeans with 6 clusters Imagen 1 Paleta de colores
t-SNE
Imagen 2 Paleta de colores
t-SNE
Imagen 3 Paleta de colores
t-SNE
Imagen 4 Paleta de colores
t-SNE
Imagen 5 Paleta de colores
t-SNE
Imagen 6 Paleta de colores
t-SNE
Imagen 7 Paleta de colores
t-SNE
Imagen 8 Paleta de colores
t-SNE
Imagen 9 Paleta de colores
t-SNE
Imagen 10 Paleta de colores
t-SNE
Para n_clusters = 7
print(f"KMeans with 7 clusters")
for i in range(len(filtered_img_classes)):
print("Imagen", i+1)
images = ImageReader(filtered_img=filtered_img_classes.iloc[[i]])
image_data_processor = ImageDataProcessor(images)
image_clustering = ImageClustering(image_data_processor, KMeans, n_clusters=7, n_init="auto")
image_clustering.fit()
print("Paleta de colores")
image_clustering.plot_clusters()
dim_reducer = DimReducer(image_data_processor, image_clustering)
print("t-SNE")
dim_reducer.plot_tsne_with_cluster_colors(2)
KMeans with 7 clusters Imagen 1 Paleta de colores
t-SNE
Imagen 2 Paleta de colores
t-SNE
Imagen 3 Paleta de colores
t-SNE
Imagen 4 Paleta de colores
t-SNE
Imagen 5 Paleta de colores
t-SNE
Imagen 6 Paleta de colores
t-SNE
Imagen 7 Paleta de colores
t-SNE
Imagen 8 Paleta de colores
t-SNE
Imagen 9 Paleta de colores
t-SNE
Imagen 10 Paleta de colores
t-SNE
A pesar de que anteriormente se había determinado que el número de clústers óptimo era 5, se decidió aplicar el algoritmo con 6 y 7 clústers para observar si se obtenían resultados más claros y precisos. Sin embargo, se observó que el número de clústers óptimo, como lo indicaba el coeficiente de silueta, era 5, ya que con 6 y 7 clústers se observaron colores muy similares y se perdieron las diferencias entre los colores de la imagen original. Por lo tanto, se concluye que el número de clústers óptimo para las imágenes seleccionadas es 5.